<script setup lang="ts">
/**
 *  qrcode.js
 *  https://www.npmjs.com/package/qrcode#qr-code-options
 *
 *
 *  该包可以解决小程序真机报：无Encodoer的异常
 *  import "fastestsmallesttextencoderdecoder"
 * （最好在app.js 或者前置页面提前引入）
 *
 *  当前这里，生成的Text可预见字符类型，简化使用自定义函数urlToBytes转码
 */

import { shallowRef, onMounted, watchEffect, nextTick } from "vue";
import Taro from "@tarojs/taro";
import qrcode from "qrcode";

/**
 * 极简方案：ASCII 直接转换
 * @param url
 */
function urlToBytes(url?: string) {
  if (!url) return "";

  const bytes = new Uint8Array(url.length);
  for (let i = 0; i < url.length; i++) {
    bytes[i] = url.charCodeAt(i);
  }
  return bytes;
}

const props = defineProps<{
  /**
   * 二维码文本
   */
  text?: string;

  /**
   * 二维码周边空白大小
   */
  margin?: number;

  /**
   * 图片大小
   */
  width?: number; // 图片大小

  /**
   *  码的颜色
   */
  darkColor?: string;

  /**
   * 整体背景色
   */
  lightColor?: string;
}>();

const emits = defineEmits<{
  success: [];
  error: [error: any];
}>();

const canvas = shallowRef();

/**
 * 创建二维码
 *
 * 如果是字母+数组，可以直接使用 toCanvas(canvas.value, text, {})
 * 如果带符合或者其他字符，小程序真机会报错：无Encoder
 *
 * 这里采用 手动编码模式，不使用qrcode插件内部textEnCode
 */
const toCreate = () => {
  const { text, margin, width, lightColor, darkColor } = props;

  qrcode
    .toCanvas(canvas.value, [{ data: urlToBytes(text), mode: "byte" }], {
      // type: "image/png",
      width,
      // scale: 10,
      // qzone: 0,
      margin,
      color: {
        // 背景
        light: lightColor,
        // 码的颜色
        dark: darkColor,
      },
    })
    .then(
      () => emits("success"),
      (err) => {
        console.error("二维码生成异常", err);
        emits("error", err);
      }
    );
};

onMounted(() => {
  Taro.createSelectorQuery()
    .select("#myCanvas")
    .fields({ node: true, size: true })
    .exec((res) => {
      canvas.value = res[0].node;

      if (props.text) nextTick(() => toCreate());
    });
});

watchEffect(() => {
  if (canvas.value) {
    toCreate();
  }
});
</script>

<template>
  <canvas type="2d" id="myCanvas" />
</template>
